using MicroMsg.Common.Utils;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace MicroMsg.Network
{
	public class SocketClient
	{
		private const int RECV_STATUS_READY = 0;
		private const int RECV_STATUS_ING = 1;
		private const int RECV_STATUS_DONE = 2;
		public const int BUFFER_SIZE = 65536;
		public Socket mSocket;
		private ManualResetEvent mClientDoneEvent = new ManualResetEvent(false);
		private int mRecvStatus;
		private int mRecvCountTrans;
		private int mRecvOffsetTrans;
		public byte[] mBufferReceived = new byte[65536];
		public static byte[] mBufferOutput = new byte[131072];
		public int mOutputLength;
		private SocketAsyncEventArgs mRecvSocketEventArg;
		private SocketError mRecvResponseResult = 10060;
		private EventHandler<SocketAsyncEventArgs> mRecvEventHandler;
		public SocketError Connect(string hostName, int portNumber)
		{
			SocketError result = 10060;
			Log.smethod_4("Network", string.Concat(new object[]
			{
				"Try connect :",
				hostName,
				": ",
				portNumber
			}));
			SocketError result2;
			try
			{
				DnsEndPoint remoteEndPoint = new DnsEndPoint(hostName, portNumber);
				this.mSocket = new Socket(2, 1, 6);
				this.mSocket.set_ReceiveBufferSize(65536);
				SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs();
				socketAsyncEventArgs.set_RemoteEndPoint(remoteEndPoint);
				socketAsyncEventArgs.add_Completed(delegate(object sender, SocketAsyncEventArgs e)
				{
                    result = e.get_SocketError();
					this.mClientDoneEvent.Set();
				});
				this.mClientDoneEvent.Reset();
				this.mSocket.ConnectAsync(socketAsyncEventArgs);
				this.mClientDoneEvent.WaitOne(10000);
				result2 = result;
			}
			catch (SocketException ex)
			{
				Log.smethod_1("Network", "socket connect failed: " + ex.get_Message());
				result2 = -1;
			}
			return result2;
		}
		public SocketError Send(byte[] data)
		{
			SocketError response = 0;
			SocketError result;
			try
			{
				if (this.mSocket != null && this.mSocket.get_Connected())
				{
					SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs();
					socketAsyncEventArgs.set_UserToken(null);
					EventHandler<SocketAsyncEventArgs> eventHandler = delegate(object sender, SocketAsyncEventArgs e)
					{
						response = e.get_SocketError();
						this.mClientDoneEvent.Set();
					};
					socketAsyncEventArgs.add_Completed(eventHandler);
					socketAsyncEventArgs.SetBuffer(data, 0, data.Length);
					this.mClientDoneEvent.Reset();
					this.mSocket.SendAsync(socketAsyncEventArgs);
					this.mClientDoneEvent.WaitOne(5000);
					result = response;
				}
				else
				{
					result = 10093;
				}
			}
			catch (SocketException ex)
			{
				Log.smethod_1("Network", "socket send failed: " + ex.get_Message());
				result = -1;
			}
			return result;
		}
		public bool isConnect()
		{
			return this.mSocket != null && this.mSocket.get_Connected();
		}
		private bool checkReady()
		{
			if (!this.isConnect())
			{
				return false;
			}
			if (this.mRecvSocketEventArg == null)
			{
				this.mRecvSocketEventArg = new SocketAsyncEventArgs();
			}
			if (this.mRecvEventHandler == null)
			{
				this.mRecvEventHandler = delegate(object sender, SocketAsyncEventArgs e)
				{
					this.onHandleBufferReady(e);
				};
				this.mRecvSocketEventArg.add_Completed(this.mRecvEventHandler);
			}
			return true;
		}
		private void onHandleBufferReady(SocketAsyncEventArgs socketAsyncEventArgs_0)
		{
			if (this.mSocket == null)
			{
				Log.smethod_1("Network", "recv data , but socket had been closed");
				return;
			}
			if (socketAsyncEventArgs_0.get_SocketError() != null)
			{
				this.mRecvResponseResult = socketAsyncEventArgs_0.get_SocketError();
				this.mRecvStatus = 2;
				return;
			}
			if (socketAsyncEventArgs_0.get_BytesTransferred() == 0)
			{
				return;
			}
			this.mRecvResponseResult = socketAsyncEventArgs_0.get_SocketError();
			this.mRecvCountTrans = socketAsyncEventArgs_0.get_BytesTransferred();
			this.mRecvOffsetTrans = socketAsyncEventArgs_0.get_Offset();
			this.appendData(this.mBufferReceived, this.mRecvOffsetTrans, this.mRecvCountTrans);
			this.mRecvStatus = 2;
			NetHandler.wakeUp();
		}
		private SocketError doReceive()
		{
			SocketError result;
			try
			{
				this.mRecvSocketEventArg.SetBuffer(this.mBufferReceived, 0, this.mBufferReceived.Length);
				this.mSocket.ReceiveAsync(this.mRecvSocketEventArg);
				result = 0;
			}
			catch (SocketException ex)
			{
				Log.smethod_1("Network", "Receive failed: " + ex.get_Message());
				result = 10053;
			}
			return result;
		}
		private void checkOutput(ref byte[] outBuf, ref int offset, ref int count)
		{
			int num = 0;
			if (!this.isRecvCompleted(ref num))
			{
				return;
			}
			outBuf = new byte[num];
			count = num;
			offset = 0;
			Buffer.BlockCopy(SocketClient.mBufferOutput, 0, outBuf, 0, num);
			if (this.mOutputLength > num)
			{
				Buffer.BlockCopy(SocketClient.mBufferOutput, num, SocketClient.mBufferOutput, 0, this.mOutputLength - num);
				this.mOutputLength -= num;
				return;
			}
			int num2 = 0;
			Util.writeInt(0, ref SocketClient.mBufferOutput, ref num2);
			this.mOutputLength = 0;
		}
		public SocketError Receive(ref byte[] outBuf, ref int offset, ref int count)
		{
			if (!this.checkReady())
			{
				return 10053;
			}
			if (this.mRecvStatus == 1)
			{
				this.checkOutput(ref outBuf, ref offset, ref count);
				return 0;
			}
			if (this.mRecvStatus == 2)
			{
				this.checkOutput(ref outBuf, ref offset, ref count);
				this.mRecvStatus = 0;
				return this.mRecvResponseResult;
			}
			if (this.mRecvStatus == 0)
			{
				this.mRecvStatus = 1;
				return this.doReceive();
			}
			return 0;
		}
		private bool isRecvCompleted(ref int totalLen)
		{
			if (this.mOutputLength < 16)
			{
				return false;
			}
			int num = 0;
			totalLen = Util.readInt(SocketClient.mBufferOutput, ref num);
			if (totalLen <= 65536 && totalLen >= 16)
			{
				return this.mOutputLength >= totalLen;
			}
			this.mOutputLength = 0;
			return false;
		}
		public void appendData(byte[] buffer, int offset, int count)
		{
			if (this.mOutputLength + count > SocketClient.mBufferOutput.Length)
			{
				this.mOutputLength = 0;
				return;
			}
			Buffer.BlockCopy(buffer, offset, SocketClient.mBufferOutput, this.mOutputLength, count);
			this.mOutputLength += count;
		}
		public void Close()
		{
			try
			{
				this.mRecvStatus = 0;
				this.mOutputLength = 0;
				if (this.mRecvSocketEventArg != null)
				{
					this.mRecvSocketEventArg.Dispose();
					this.mRecvSocketEventArg = null;
				}
				this.mRecvEventHandler = null;
				if (this.mSocket != null)
				{
					this.mSocket.Dispose();
					this.mSocket.Close();
					this.mSocket = null;
				}
			}
			catch (SocketException ex)
			{
				Log.smethod_1("Network", "socket close failed: " + ex.get_Message());
			}
		}
	}
}
